package com.syp.auth.service.business.impl;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.syp.auth.common.Constants;
import com.syp.auth.common.ImageVCGenerator;
import com.syp.auth.dao.po.ResourceEntity;
import com.syp.auth.dao.po.RoleResourceEntity;
import com.syp.auth.dao.po.UserEntity;
import com.syp.auth.dao.po.UserRoleEntity;
import com.syp.auth.dao.repository.ResourceRepository;
import com.syp.auth.dao.repository.RoleResourceRepository;
import com.syp.auth.dao.repository.UserRepository;
import com.syp.auth.dao.repository.UserRoleRepository;
import com.syp.auth.domain.enums.ResourceIsDefaultEnum;
import com.syp.auth.domain.vo.ResourceVo;
import com.syp.auth.export.common.GeneralAccessVo;
import com.syp.auth.export.common.GeneralUserVo;
import com.syp.auth.export.common.GorgeousParameters;
import com.syp.auth.service.business.AuthorizeServiceI;
import com.syp.auth.util.MD5Util;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class AuthorizeServiceImpl implements AuthorizeServiceI {

	@Autowired
	private UserRepository userRepository;
	@Autowired
	private UserRoleRepository userRoleRepository;
	@Autowired
	private ResourceRepository resourceRepository;
	@Autowired
	private RoleResourceRepository roleResourceRepository;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@Override
	public void dsignin(GeneralUserVo guser, GeneralAccessVo gaccess, HttpServletResponse httpResponse) {
		UserEntity userEntity = this.userRepository.signin(guser.getUserCode(), MD5Util.md5(guser.getPassword()));
		if (userEntity != null) {
			BeanUtils.copyProperties(userEntity, guser);

			if (userEntity.getId() == Constants.SUPER_MAN_NO) {
				List<ResourceEntity> rs = this.resourceRepository.getByAppCode(gaccess.getApp());
				for (ResourceEntity resourceEntity : rs) {
					ResourceVo resource = new ResourceVo();

					resource.setId(resourceEntity.getId());
					resource.setResCode(resourceEntity.getResCode());
					resource.setResName(resourceEntity.getResName());
					resource.setResUrl(resourceEntity.getResUrl());
					resource.setResType(resourceEntity.getResType());
					resource.setIsDefault(resourceEntity.getIsDefault());

					guser.getPermitResList().add(resource);
					if (resource.getResUrl() != null && !resource.getResUrl().isEmpty()) {
						guser.getPermitUrlList().add(resourceEntity.getResUrl());
					}
				}
			} else {
				List<UserRoleEntity> urs = this.userRoleRepository.getByUserId(userEntity.getId());
				if (urs != null && !urs.isEmpty()) {
					for (UserRoleEntity ur : urs) {
						List<RoleResourceEntity> roleResourceEntityList = this.roleResourceRepository.getByRoleId(ur.getRoleId());
						for (RoleResourceEntity rrs : roleResourceEntityList) {
							ResourceEntity resourceEntity = this.resourceRepository.findOne(rrs.getResId());
							if (resourceEntity.getAppCode() != null && gaccess.getApp().equals(resourceEntity.getAppCode())) {
								ResourceVo resource = new ResourceVo();

								resource.setId(resourceEntity.getId());
								resource.setResCode(resourceEntity.getResCode());
								resource.setResName(resourceEntity.getResName());
								resource.setResUrl(resourceEntity.getResUrl());
								resource.setResType(resourceEntity.getResType());
								resource.setIsDefault(resourceEntity.getIsDefault());

								guser.getPermitResList().add(resource);
								if (resource.getResUrl() != null && !resource.getResUrl().isEmpty()) {
									guser.getPermitUrlList().add(resourceEntity.getResUrl());
								}
							}
						}
					}
				}
			}

			long indexResCount = 0;
			for (ResourceVo res : guser.getPermitResList()) {
				if (res.getIsDefault() == ResourceIsDefaultEnum.TRUE.getCode()) {
					indexResCount++;
				}
			}
			if (indexResCount > 0) {
				final String tokenKey = GorgeousParameters.SESSION_ID_PREFIX + gaccess.getSid();
				final String tokenValue = JSON.toJSONString(guser);
				this.stringRedisTemplate.opsForValue().set(tokenKey, tokenValue, GorgeousParameters.TOKEN_EXISTS_HOURS, TimeUnit.HOURS);
			} else {
				log.info("用户：[{}]没有登录系统：[{}]的权限，请联系管理员", guser.getUserCode(), gaccess.getApp());
			}
		}
	}

	@Override
	public boolean verify(String sid) {
		final String tokenKey = GorgeousParameters.SESSION_ID_PREFIX + sid;
		return this.stringRedisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				try {
					boolean exists = connection.exists(tokenKey.getBytes(GorgeousParameters.CHARSET_UTF8));
					if (exists) {
						return stringRedisTemplate.expire(tokenKey, GorgeousParameters.TOKEN_EXISTS_HOURS, TimeUnit.HOURS);
					}
					return false;
				} catch (UnsupportedEncodingException e) {
					log.error("不支持的编码方式。", e);
					return false;
				}
			}
		});

	}

	@Override
	public void ivCode(String sid, HttpServletResponse httpResponse) {
		ByteArrayOutputStream out = null;
		try {
			out = new ByteArrayOutputStream();

			final String vcKey = GorgeousParameters.IVC_PREFIX + sid;
			final String vcValue = ImageVCGenerator.getInstunce().build(out, GorgeousParameters.IVC_WIDTH, GorgeousParameters.IVC_HEIGHT);

			this.stringRedisTemplate.opsForValue().set(vcKey, vcValue, 300, TimeUnit.SECONDS);

			httpResponse.reset();
			httpResponse.setHeader("Pragma", "No-cache");
			httpResponse.setHeader("Cache-Control", "no-cache");
			httpResponse.setDateHeader("Expires", 0);
			httpResponse.setContentType("image/jpeg");
			httpResponse.getOutputStream().write(out.toByteArray());
			httpResponse.getOutputStream().flush();
		} catch (Exception e) {
			log.error("验证码获取失败。", e);
		} finally {
			try {
				out.flush();
				out.close();
			} catch (Exception e) {
				log.error("关闭输出流异常。", e);
			}
		}
	}

	@Override
	public void signout(String sid) {
		String key = GorgeousParameters.SESSION_ID_PREFIX + sid;
		stringRedisTemplate.delete(key);
	}

	@Override
	public GeneralUserVo getCurrentUser(String sid) {
		final String tokenKey = GorgeousParameters.SESSION_ID_PREFIX + sid;
		String jsonText = this.stringRedisTemplate.opsForValue().get(tokenKey);
		if (jsonText != null && !jsonText.equals("")) {
			JSONObject json = JSON.parseObject(jsonText);
			return JSON.toJavaObject(json, GeneralUserVo.class);
		}

		return null;
	}

}